
#ifndef Velyn_TriangleMesh_h
#define Velyn_TriangleMesh_h

#include <iostream>
#include <vector>

#include "Vertex.h"

namespace Velyn {
    
    namespace Object {
    
        /*
         * Specifies a triangle mesh.
         */
        class TriangleMesh {
        
        private:
            
            /*
             * 
             */
            std::vector<Vertex> vertexList;
            
            /*
             * This is the triangle index listing that contains the corresponding index 
             * for where each vertex is stored in vertexList. Vertex indices are 
             * stored into the vector in threes which makes up one triangle.
             *
             * This is an example how information is retrieved from triangleIndexList:
             * int triangle = 0 // for triangle 0 or the first triangle in the list
             * int triangleIndex = triangle * 3 // because there are three vertex indices per triangle
             * vertex[0] = triangleIndexList[triangleIndex]
             * vertex[1] = triangleIndexList[triangleIndex + 1]
             * vertex[2] = triangleIndexList[triangleIndex + 2]
             */
            std::vector<int> triangleIndexList;
            
            /*
             *
             */
            int numberTriangles;
            
            /*
             *
             */
            int numberVertices;
            
        public:
            
            /*
             * Default constructor.
             */
            TriangleMesh() {}
            
            /*
             * Constructor that allow the TriangleMesh to have a Drawable.
             */
            TriangleMesh(/*Drawable*/) {}
            
            /*
             * @param
             */
            void addVertex(const Vertex vertex) {
                vertexList.push_back(vertex);
            }
            
            /*
             * @param
             */
            void addVertex(const float px, const float py, const float pz,
                           const float nx, const float ny, const float nz,
                           const float tu, const float tv) {
            
                Vertex vertex;
                
                vertex.setPosition(px, py, pz);
                vertex.setNormal(nx, ny, nz);
                vertex.setTexture(tu, tv);
                
                vertexList.push_back(vertex);
                
                numberVertices++;
            }
            
            /*
             * @return
             */
            void addTriangle(const int triangleIndex0, const int triangleIndex1, const int triangleIndex2) {
                triangleIndexList.push_back(triangleIndex0);
                triangleIndexList.push_back(triangleIndex1);
                triangleIndexList.push_back(triangleIndex2);
                
                numberTriangles++;
            }
            
            /*
             * @param
             */
            std::vector<Vertex> getVertexList(int triangleIndex) {
                int triangleIndex = triangle * 3;

                std::vector<Vertex> vertices(3);
                
                // TODO: if this trys to access a part of the vector that does not exist
                // throw an error
                
                vertices[0] = vertexList[triangleIndexList[triangleIndex]];
                vertices[1] = vertexList[triangleIndexList[triangleIndex + 1]];
                vertices[2] = vertexList[triangleIndexList[triangleIndex + 2]];
                
                return vertices;
            }
            
            /*
             * @param
             */
            
            // TODO: replaces a triangle with a set triangles
            void replace(int triangle, std::vector<int> newTriangles) {
                // delete the given triangle
                
                // add in the new triangles in its place
            }
            
            /*
             * @return
             */
            int getNumberVertices() {
                return numberVertices;
            }
            
            /*
             * @return
             */
            int getNumberTriangles() {
                return numberTriangles;
            }
            
            /*
             * @return
             */
            int size() {
                return numberTriangles;
            }
            
            /*
             * Print out the triangle indices and their corresponding vertices
             * for each triangle in the mesh.
             */
            void print() {
                std::out << "Mesh Information: \n";
                
                // for each triangle
                for(int triangle = 0; triangle < numberTriangles; triangle++) {
                    
                    // get the corresponding triangle index
                    int triangleIndex = triangle * 3;
                    
                    std::cout << "Triangle: " << triangleIndex;
                    std::cout << "Triangle Indices: ";
                    std::cout << "[ " << triangleIndexList[triangleIndex] << " " 
                                      << triangleIndexList[triangleIndex + 1] << " " 
                                      << triangleIndexList[triangleIndex + 2] << " ]\n";
                    std::cout << "Vertex Coordinates: ";
                    vertexList[triangleIndexList[triangleIndex]].print();
                    vertexList[triangleIndexList[triangleIndex + 1]].print();
                    vertexList[triangleIndexList[triangleIndex + 2]].print();  
                }
                
                std::cout << '\n';
            }
        };
    }
}

#endif
